package com.yfp.operation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.yfp.common.core.domain.R;
import com.yfp.common.core.domain.Response;
import com.yfp.common.core.domain.ResponseEnum;
import com.yfp.common.datascope.annotation.DataScope;
import com.yfp.minapp.auth.api.RemoteClientService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.yfp.operation.domain.Client;
import com.yfp.operation.domain.ClientBill;
import com.yfp.operation.domain.MachineDO;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.domain.vo.StoredBillVO;
import com.yfp.operation.mapper.ClientBillMapper;
import com.yfp.operation.mapper.ClientCouponMapper;
import com.yfp.operation.domain.OrderComboDO;
import com.yfp.operation.domain.dto.MarCouponPackReceiveUserReqDTO;
import com.yfp.operation.domain.dto.UserLayerTotalUserDTO;
import com.yfp.operation.enums.UserLabelEnums;
import com.yfp.operation.mapper.ClientMapper;
import com.yfp.operation.mapper.MachineMapper;
import com.yfp.operation.service.ClientService;
import com.yfp.operation.domain.dto.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import com.yfp.operation.service.OrderComboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 客户Service
 *
 * @CreateDate: 2024/5/16 9:59
 * @UpdateUser:
 * @UpdateDate: 2024/5/16 9:59
 * @UpdateRemark: 暂无修改
 * @Version: 1.0
 */
@Service
@Slf4j
public class ClientServiceImpl implements ClientService {

    @Autowired
    private ClientMapper clientMapper;
    @Resource
    private OrderComboService orderComboService;
    @Resource
    private ClientBillMapper clientBillMapper;
    @Resource
    private RemoteClientService remoteClientService;
    @Resource
    private ClientCouponMapper clientCouponMapper;
    @Resource
    private MachineMapper machineMapper;

    @Override
    public List<Client> findList(Client client) {
        return clientMapper.findList(client);
    }

    @Override
    @Transactional
    public void edit(Client client) {
        clientMapper.edit(client);
    }

    /**
     * 根据用户id查询客户信息
     *
     * @param userId
     * @return
     */
    @Override
    public Client getByUserId(String userId) {
        Client client = clientMapper.getById(userId);
        return client;
    }

    @Override
    public List<Client> listByReceiveUserReq(MarCouponPackReceiveUserReqDTO receiveUserReqDTO) {
        return clientMapper.selectByCouponPackId(receiveUserReqDTO);
    }

    @Override
    public List<Client> listByUserLayerTotalUserDTO(UserLayerTotalUserDTO userLayerDTO, List<String> userMobiles) {
        if (CollUtil.isEmpty(userMobiles)) {
            return Collections.emptyList();
        }
        return clientMapper.listByUserLayerTotalUserDTO(userLayerDTO, userMobiles);
    }

    public static <T> List<List<T>> groupBySize(List<T> list, int groupSize) {
        if (groupSize <= 0) {
            throw new IllegalArgumentException("Group size must be greater than 0");
        }

        List<List<T>> result = new ArrayList<>();
        int totalGroups = (int) Math.ceil((double) list.size() / groupSize);

        for (int i = 0; i < totalGroups; i++) {
            int fromIndex = i * groupSize;
            int toIndex = Math.min(fromIndex + groupSize, list.size());
            List<T> group = list.subList(fromIndex, toIndex);
            result.add(group);
        }

        return result;
    }

    @Override
    public void clientLabel() {
        Client client = new Client();
        client.setStatus(1);
        List<Client> clientList = clientMapper.findList(client);

        int groupSize = 50;
        List<List<Client>> listss = groupBySize(clientList, groupSize);
        for (List<Client> lists : listss) {
            List<String> clientIds = lists.stream().map(Client::getId).collect(Collectors.toList());
            Map<String, List<OrderComboDO>> groupedByUserId = orderComboService.listByUserIds(clientIds).stream().collect(Collectors.groupingBy(OrderComboDO::getUserId));

            Map<String, UserLabelEnums> userLabels = groupedByUserId.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> calculateClientLabel(entry.getKey(), entry.getValue())));

            lists.forEach(client1 -> {
                if (userLabels.containsKey(client1.getId())) {
                    Integer type = userLabels.get(client1.getId()).getType();
                    if (!Objects.equals(client1.getLabel(), type)) {
                        client1.setLabel(type);
                        clientMapper.updateLabelById(client1);
                    }
                }
            });
        }
    }

    @Override
    public UserLabelEnums calculateClientLabel(String key, List<OrderComboDO> orderComboDOS) {
        // 活跃用户数	        近一周下单次数≥2（以手机号出现次数为准）
        // 流失用户数	        订单数>1，但近 3 个月未消费
        // 僵尸用户数	        订单数>1，但近 1 个月未消费
        // 高潜流失用户数	    订单数>10，但近 1 个月未消费
        // 高价值用户数量	    GMV≥300,消费频次≥30，消费间隔≤7（包含券包），当前时间近7天内消费了
        DateTime date = DateUtil.date();

        DateTime offset7day = date.offsetNew(DateField.DAY_OF_MONTH, -7);
        BigDecimal priceGmv = orderComboDOS.stream().map(item -> NumberUtil.toBigDecimal(item.getPrice())).reduce(BigDecimal.ZERO, BigDecimal::add);
        boolean isFrequency = orderComboDOS.stream().count() >= 30;
        long count5 = orderComboDOS.stream().filter(item -> DateUtil.isIn(item.getCreateTime(), offset7day, date)).count();
        boolean isInterval7 = count5 >= 1;
        List<OrderComboDO> sortedList = orderComboDOS.stream().sorted(Comparator.comparing(OrderComboDO::getCreateTime)).collect(Collectors.toList());
        boolean isInterval = sortedList.stream().skip(1).allMatch(item -> DateUtil.between(item.getCreateTime(), sortedList.get(sortedList.indexOf(item) - 1).getCreateTime(), DateUnit.DAY) <= 7);
        if (isInterval7 && isFrequency && isInterval && NumberUtil.isGreaterOrEqual(priceGmv, new BigDecimal("300"))) {
            return UserLabelEnums.HIGH_VALUE;
        }

        long count1 = orderComboDOS.stream().filter(item -> DateUtil.isIn(item.getCreateTime(), offset7day, date)).count();
        if (count1 >= 2) {
            return UserLabelEnums.ACTIVE;
        }

        DateTime offset3Month = date.offsetNew(DateField.MONTH, -3);
        long count2 = orderComboDOS.stream().filter(item -> DateUtil.isIn(item.getCreateTime(), offset3Month, date)).count();
        if (count2 == 0) {
            return UserLabelEnums.LOST;
        }

        DateTime offset1Month = date.offsetNew(DateField.MONTH, -1);
        long count34 = orderComboDOS.stream().filter(item -> DateUtil.isIn(item.getCreateTime(), offset1Month, date)).count();
        if (count34 == 0 && orderComboDOS.stream().count() >= 10) {
            return UserLabelEnums.HIGH_LOST;
        }
        if (count34 == 0) {
            return UserLabelEnums.ZOMBIE;
        }
        return UserLabelEnums.DEFAULT_LABEL;
    }

    @Override
    public List<Client> client2VO(List<Client> list) {
        for (Client client : list) {
            client.setLabelName(UserLabelEnums.getLabel(client.getLabel()));
        }
        return list;
    }

    @Override
    public List<Client> listByUserIds(List<String> notifyCouponArriveReminderList) {
        if (CollUtil.isEmpty(notifyCouponArriveReminderList)) {
            return List.of();
        }
        return clientMapper.selectByUserIds(notifyCouponArriveReminderList);
    }
    /**
     * 储值余额管理列表
     * @param surplusFundingDTO
     * @return
     */
    @Override
    public List<StoredBillVO> surplusFunding(SurplusFundingDTO surplusFundingDTO) {
        return clientMapper.surplusFunding(surplusFundingDTO);
    }

    /**
     * 储值记录
     * @param storedBillDTO
     * @return
     */
    @Override
    @DataScope(deptAlias = "sva")
    public List<StoredBillVO> storedBill(StoredBillDTO storedBillDTO) {
        return clientBillMapper.storedBill(storedBillDTO);
    }

    /**
     * 余额变动记录
     * @param clientBillsDTO
     * @return
     */
    @Override
    public List<ClientBill> clientBills(ClientBillsDTO clientBillsDTO) {
        return clientBillMapper.clientBills(clientBillsDTO);
    }

    /**
     * 数据补全
     * @param storedBillVOS
     * @return
     */
    @Override
    public List<StoredBillVO> storedBillComplement(List<StoredBillVO> storedBillVOS) {

        if (CollUtil.isEmpty(storedBillVOS)) {
            return storedBillVOS;
        }

        for (StoredBillVO storedBillVO : storedBillVOS) {
            // 判断是否为首充
            Integer count = clientBillMapper.getCount(storedBillVO.getCreateTime(),storedBillVO.getClientId());
            if (count == 0) {
                // 首充优惠券信息
                StoredBillVO oneRechargeVo = clientBillMapper.oneRechargeCoupon(storedBillVO.getClientId(),storedBillVO.getActivityId(),storedBillVO.getCbId());
                if (!BeanUtil.isEmpty(oneRechargeVo) && oneRechargeVo.getOneRechargeCouponId() != null) {
                    storedBillVO.setOneRechargeCouponId(oneRechargeVo.getOneRechargeCouponId());
                    storedBillVO.setOneRechargeCouponCount(oneRechargeVo.getOneRechargeCouponCount());
                    storedBillVO.setOneRechargeCouponName(oneRechargeVo.getOneRechargeCouponName());
                }
            }
        }

        return storedBillVOS;
    }

    /**
     * 储值退款
     * @param storedRefundDTO
     */
    @Override
    public R<?> refund(StoredRefundDTO storedRefundDTO) {

        Client client = clientMapper.getById(storedRefundDTO.getClientId());
        BigDecimal surplusMoney = clientBillMapper.surplusMoney(storedRefundDTO.getClientId());
        if (storedRefundDTO.getRefundMoney().compareTo(client.getBalance()) != 0 || client.getBalance().compareTo(surplusMoney) != 0) {
            return R.fail("储值余额退款失败，余额发生变动");
        }

        Response<Boolean> booleanResponse = remoteClientService.storedRefund(storedRefundDTO.getClientId());
        log.info("退款结果{}", booleanResponse);
        if (!booleanResponse.getCode().equals(ResponseEnum.OPERATOR_SUCCESS.getCode())) {
            log.error("退款失败{}", booleanResponse);
            return R.fail(booleanResponse.getMsg());
        }

        return R.ok();
    }


    /**
     * 给进社群的新客户打点位标签
     */
    @Override
    @Transactional
    public void newClientPositionLabel() {
        // 获取进群时间比客户打标签时间晚的客户
        List<Client> clients = clientMapper.getClientPosition();
        log.info("修改标签的客户:{}",clients);
        if (!CollUtil.isEmpty(clients)) {
            // 更新点位标签
            clientMapper.updatePositionId(clients);
        }
    }


    /**
     * 修改客户点位标签
     * @param orderId
     */
    @Override
    public void updatePositionId(String orderId) {
        log.info("订单完成修改客户点位标签，订单id:{}",orderId);
        OrderComboDO orderComboDO = orderComboService.getById(orderId);
        MachineDO machine = machineMapper.getMachine(orderComboDO.getMachineId());
        if (!BeanUtil.isEmpty(machine)) {
            clientMapper.amendPositionId(orderComboDO.getUserId(),machine.getPositionId());
        }
    }

}
